import tkinter as tk
from tkinter import ttk
import ttkbootstrap as ttkb
from PIL import Image, ImageTk
import os
import time
from utils import resource_path
from .messagebox_custom import CustomMessageBox
from services import ExamService, FavoriteService
from app_state import app_state
from configs.config import FONT_CONFIG

class ExamView(tk.Frame):
    """考试视图类，负责考试界面的UI展示和逻辑处理"""

    def __init__(self, root, exam_id, exam_questions, exam_config, font=None, question_font=None, on_back=None):
        super().__init__(root)
        self.root = root
        self.exam_service = ExamService()
        self.favorite_service = FavoriteService()
        self.exam_id = exam_id
        self.exam_questions = exam_questions
        self.exam_config = exam_config
        self.font = font or FONT_CONFIG['default']
        self.question_font = question_font or FONT_CONFIG['question']
        self.title_font = FONT_CONFIG['title']
        self.on_back = on_back
        self.current_index = 0
        self.exam_answers = {}
        self.exam_submitted = False
        self.exam_start_time = time.time()
        self.exam_end_time = self.exam_start_time + exam_config['time'] * 60

        # 创建UI组件
        self.create_widgets()

    def create_widgets(self):
        # print("create_widgets")
        """创建考试界面的所有UI组件"""
        # 清空窗口
        for widget in self.root.winfo_children():
            widget.destroy()

        # 创建返回按钮 - 图片形式
        back_img = Image.open(resource_path(os.path.join("icon", "back.png")))
        back_img = back_img.resize((30, 30), Image.Resampling.LANCZOS)
        back_photo = ImageTk.PhotoImage(back_img)
        back_btn = tk.Label(self.root, image=back_photo, cursor="hand2")
        back_btn.image = back_photo  # 保持引用
        back_btn.bind("<Button-1>", lambda e: self.on_back_with_invalidation())
        back_btn.pack(anchor=tk.NW, pady=10, padx=10)

        # 显示考试信息
        info_text = f"{app_state.current_category}类考试 - 共{self.exam_config['total']}题"
        info_label = tk.Label(self.root, text=info_text, font=self.font)
        info_label.pack(pady=10)

        # 显示考试时间
        time_label = tk.Label(self.root, text=f"答题时间: {self.exam_config['time']}分钟", font=self.font)
        time_label.pack(pady=5)

        # 创建计时器标签
        self.timer_label = tk.Label(self.root, text="剩余时间: 00:00", font=self.font)
        self.timer_label.pack(pady=5)

        # 更新计时器
        self.update_timer()

        # 显示第一题
        if self.exam_questions and len(self.exam_questions) > 0:
            self.display_question(self.exam_questions[0], current_index=0)
        else:
            CustomMessageBox.showinfo("提示", f"没有找到{self.current_category}类题目", parent=self.root)
            self.on_back()

    def display_question(self, question, current_index=0):
        """显示单个题目"""
        # 保存当前索引
        self.current_index = current_index

        # 清空除了返回按钮和计时器标签外的所有控件
        for widget in self.root.winfo_children()[1:]:
            if hasattr(self, 'timer_label') and widget == self.timer_label:
                continue  # 跳过计时器标签
            widget.destroy()

        # 创建主容器
        main_container = tk.Frame(self.root)
        main_container.pack(fill=tk.BOTH, expand=True, pady=10, padx=20)

        # 题目框架
        question_frame = tk.Frame(main_container)
        question_frame.pack(fill=tk.BOTH, expand=True)

        # 创建题干和收藏按钮同一行的框架
        q_and_favorite_frame = tk.Frame(question_frame)
        q_and_favorite_frame.pack(fill=tk.X, pady=10)

        # 左侧题干区域
        q_text_frame = tk.Frame(q_and_favorite_frame)
        q_text_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

        # 右侧收藏按钮区域
        favorite_frame = tk.Frame(q_and_favorite_frame, width=60, height=60)
        favorite_frame.pack(side=tk.RIGHT, padx=10, anchor=tk.NE)
        favorite_frame.pack_propagate(False)
        favorite_frame.lift()

        # 初始状态检查
        favorite_questions = self.favorite_service.get_favorite_questions(app_state.current_user_id, app_state.current_category)
        is_favorite = any(q.id == question.id for q in favorite_questions)
        img_path = resource_path(os.path.join('icon', 'favorite_on.png')) if is_favorite else resource_path(os.path.join('icon', 'favorite_off.png'))

        # 使用PIL调整图片大小
        image = Image.open(img_path)
        image = image.resize((30, 30), Image.LANCZOS)
        favorite_img = ImageTk.PhotoImage(image)

        # 收藏按钮 - 开关样式
        def update_favorite_icon():
            nonlocal favorite_img
            # 使用favorite_service获取收藏题目
            favorite_questions = self.favorite_service.get_favorite_questions(app_state.current_user_id, app_state.current_category)
            is_favorite = any(q.id == question.id for q in favorite_questions)
            img_path = resource_path(os.path.join('icon', 'favorite_on.png')) if is_favorite else resource_path(os.path.join('icon', 'favorite_off.png'))
            # 调整新图片大小
            image = Image.open(img_path)
            image = image.resize((30, 30), Image.LANCZOS)
            favorite_img = ImageTk.PhotoImage(image)
            favorite_btn.config(image=favorite_img)
            favorite_btn.image = favorite_img  # 保持引用
            return is_favorite

        # 确保框架可见
        favorite_frame.update_idletasks()

        # 创建图片标签作为收藏按钮
        favorite_btn = tk.Label(favorite_frame, image=favorite_img, cursor="hand2")
        favorite_btn.image = favorite_img  # 保持引用
        favorite_btn.bind("<Button-1>", lambda e: toggle_favorite())
        favorite_btn.pack(pady=5)

        # 在收藏图片下方添加'收藏'文字标签
        favorite_label = tk.Label(favorite_frame, text='收藏', fg='white', bg=favorite_frame['bg'])
        favorite_label.pack(pady=(2, 0))

        # 显示题号、题型和题干
        question_number = current_index + 1
        total_questions = len(self.exam_questions)

        def toggle_favorite():
            is_favorite = update_favorite_icon()
            if is_favorite:
                self.favorite_service.remove_favorite_question(app_state.current_user_id, question.id)
            else:
                self.favorite_service.add_favorite_question(app_state.current_user_id, question.id, app_state.current_category)
            update_favorite_icon()

        type_text = "单选题" if question.type == 1 else "多选题"
        question_text = f"第{question_number}/{total_questions}题 ({type_text}): {question.Q}"
        q_label = tk.Label(q_text_frame, text=question_text, anchor=tk.CENTER,
                          font=self.question_font, wraplength=900, justify=tk.LEFT)
        q_label.pack(anchor=tk.W)

        # 显示图片(如果有)
        if hasattr(question, 'F') and question.F and question.F.startswith('data:image/png;base64,'):
            try:
                import base64
                from io import BytesIO

                # 提取base64数据
                base64_data = question.F.split(',')[1]
                # 解码base64数据
                image_data = base64.b64decode(base64_data)
                # 创建BytesIO对象
                image_buffer = BytesIO(image_data)
                # 打开图片
                image = Image.open(image_buffer)
                # 调整图片大小，保持宽高比
                max_width = 500
                max_height = 180
                width, height = image.size
                aspect_ratio = width / height
                if width > max_width:
                    width = max_width
                    height = int(width / aspect_ratio)
                if height > max_height:
                    height = max_height
                    width = int(height * aspect_ratio)
                image = image.resize((width, height), Image.LANCZOS)
                # 转换为Tkinter可用的图片
                tk_image = ImageTk.PhotoImage(image)
                # 创建标签显示图片
                img_label = tk.Label(question_frame, image=tk_image)
                img_label.image = tk_image  # 保持引用
                img_label.pack(pady=10)
            except Exception as e:
                # 如果处理失败，显示错误信息
                img_label = tk.Label(question_frame, text=f"[图片加载失败: {str(e)}]", font=self.font, fg='red')
                img_label.pack(pady=10)

        # 重置用户答案变量
        self.user_answers = []  # 用于多选题

        # 显示选项
        options_frame = tk.Frame(question_frame)
        options_frame.pack(anchor=tk.W, pady=10)

        # 选项列表
        options = [
            ('A', question.A),
            ('B', question.B),
            ('C', question.C),
            ('D', question.D)
        ]

        if question.type == 1:  # 单选题
            # 先销毁所有已有的单选按钮
            for widget in options_frame.winfo_children():
                widget.destroy()

            # 确保没有残留的变量绑定
            if hasattr(self, 'user_answer'):
                del self.user_answer

            # 重新创建单选按钮变量
            self.user_answer = tk.StringVar(value='-1')

            # 如果有已保存的答案，加载它
            if question.id in self.exam_answers:
                saved_answer, _ = self.exam_answers[question.id]
                self.user_answer.set(saved_answer)

            for opt_key, opt_text in options:
                if opt_text:
                    # 创建Frame包含按钮和标签
                    opt_frame = ttk.Frame(options_frame, cursor="hand2")
                    opt_frame.pack(anchor=tk.W, pady=5, fill=tk.X)
                    # 为Frame添加点击事件
                    def toggle_radio(event, key=opt_key):
                        self.user_answer.set(key)
                    opt_frame.bind("<Button-1>", toggle_radio)

                    # 单选按钮
                    rb = ttk.Radiobutton(opt_frame, variable=self.user_answer, value=opt_key)
                    rb.pack(side=tk.LEFT, padx=(0, 5))

                    # 选项文本标签(支持自动换行)
                    opt_label = ttk.Label(opt_frame, text=f"{opt_key}. {opt_text}",
                                          wraplength=900, anchor=tk.W, justify=tk.LEFT, cursor="hand2")
                    opt_label.pack(side=tk.LEFT, fill=tk.X)
                    # 为标签添加点击事件
                    opt_label.bind("<Button-1>", toggle_radio)
        else:  # 多选题
            self.user_answers = []
            for opt_key, opt_text in options:
                if opt_text:
                    # 创建Frame包含按钮和标签
                    opt_frame = ttk.Frame(options_frame, cursor="hand2")
                    opt_frame.pack(anchor=tk.W, pady=5, fill=tk.X)

                    var = tk.BooleanVar()
                    self.user_answers.append((opt_key, var))
                    # 为Frame添加点击事件
                    def toggle_check(event, key=opt_key, v=var):
                        v.set(not v.get())
                    opt_frame.bind("<Button-1>", toggle_check)

                    # 复选按钮
                    cb = ttk.Checkbutton(opt_frame, variable=var)
                    cb.pack(side=tk.LEFT, padx=(0, 5))

                    # 选项文本标签(支持自动换行)
                    opt_label = ttk.Label(opt_frame, text=f"{opt_key}. {opt_text}",
                                          wraplength=900, anchor=tk.W, justify=tk.LEFT, cursor="hand2")
                    opt_label.pack(side=tk.LEFT, fill=tk.X)
                    # 为标签添加点击事件
                    opt_label.bind("<Button-1>", toggle_check)

            # 如果有已保存的答案，加载它
            if question.id in self.exam_answers:
                saved_answer, _ = self.exam_answers[question.id]
                for opt_key, var in self.user_answers:
                    if opt_key in saved_answer:
                        var.set(True)

        # 按钮框架 - 固定在底部
        btn_frame = tk.Frame(self.root)
        btn_frame.pack(side=tk.BOTTOM, pady=20, fill=tk.X, padx=20)

        # 确保main_container不会被btn_frame遮挡
        main_container.pack_propagate(False)

        # 创建按钮组框架 - 放置在底部布局的右侧
        button_group_frame = tk.Frame(btn_frame)
        button_group_frame.pack(side=tk.RIGHT, padx=20, pady=5)

        # 上一题按钮 - 始终显示，交卷后或第一题时禁用
        prev_img_path = resource_path(os.path.join("icon", "last_disabled.png")) if self.exam_submitted or current_index == 0 else resource_path(os.path.join("icon", "last.png"))
        prev_img = Image.open(prev_img_path)
        prev_img = prev_img.resize((30, 30), Image.Resampling.LANCZOS)
        prev_photo = ImageTk.PhotoImage(prev_img)
        prev_btn = tk.Label(button_group_frame, image=prev_photo, cursor="hand2")
        prev_btn.image = prev_photo  # 保持引用
        if not self.exam_submitted and current_index != 0:
            prev_btn.bind("<Button-1>", lambda e: [self.save_current_answer(question),
                                                    self.display_question(self.exam_questions[current_index - 1],
                                                                          current_index=current_index - 1)])
        prev_btn.pack(side=tk.LEFT, padx=10)

        # 下一题/交卷按钮
        if self.exam_submitted or current_index >= len(self.exam_questions) - 1:
            # 最后一题或已交卷时显示禁用的交卷图片
            btn_img_path = resource_path(os.path.join("icon", "submit_disabled.png")) if self.exam_submitted else resource_path(os.path.join("icon", "submit.png"))
            btn_img = Image.open(btn_img_path)
            btn_img = btn_img.resize((30, 30), Image.Resampling.LANCZOS)
            btn_photo = ImageTk.PhotoImage(btn_img)
            btn = tk.Label(button_group_frame, image=btn_photo, cursor="hand2")
            btn.image = btn_photo  # 保持引用
            if not self.exam_submitted:
                btn.bind("<Button-1>", lambda e: [self.save_current_answer(question),
                                                 self.submit_exam()])
        else:
            # 非最后一题时显示下一题图片
            btn_img_path = resource_path(os.path.join("icon", "next.png"))
            btn_img = Image.open(btn_img_path)
            btn_img = btn_img.resize((30, 30), Image.Resampling.LANCZOS)
            btn_photo = ImageTk.PhotoImage(btn_img)
            btn = tk.Label(button_group_frame, image=btn_photo, cursor="hand2")
            btn.image = btn_photo  # 保持引用
            btn.bind("<Button-1>", lambda e: [self.save_current_answer(question),
                                            self.display_question(self.exam_questions[current_index + 1],
                                                                  current_index=current_index + 1)])
        btn.pack(side=tk.LEFT, padx=10)

    def save_current_answer(self, question):
        """保存当前题目的答案"""
        if question.type == 1:  # 单选题
            user_answer = self.user_answer.get()
            correct_answer = question.T
            is_correct = user_answer == correct_answer if user_answer and user_answer != '-1' else False
            self.exam_answers[question.id] = (user_answer, is_correct)
        else:  # 多选题
            user_answer = ''.join([opt_key for opt_key, var in self.user_answers if var.get()])
            correct_answer = question.T
            is_correct = user_answer == correct_answer if user_answer else False
            self.exam_answers[question.id] = (user_answer, is_correct)

    def on_back_with_invalidation(self):
        """
        返回时处理未交卷的情况，作废考试记录
        """
        if not self.exam_submitted:
            # 询问用户是否确认退出并作废考试
            result = CustomMessageBox.askyesno("确认", "考试尚未提交，退出将作废本次考试记录，是否继续？", parent=self.root)
            if result:
                # 作废考试记录
                self.exam_service.invalidate_exam(self.exam_id)
                # 调用回调函数返回主界面
                if self.on_back:
                    self.on_back()
        else:
            # 考试已提交，直接返回
            if self.on_back:
                self.on_back()

    def update_timer(self):
        """更新计时器显示"""
        # 检查计时器标签是否仍然存在
        if not hasattr(self, 'timer_label') or not self.timer_label.winfo_exists():
            return
        # 计算剩余时间
        current_time = time.time()
        remaining_time = max(0, self.exam_end_time - current_time)
        minutes = int(remaining_time // 60)
        seconds = int(remaining_time % 60)

        # 更新标签
        try:
            self.timer_label.config(text=f"剩余时间: {minutes:02d}:{seconds:02d}")
        except Exception as e:
            # 如果更新失败（例如标签已被销毁），直接返回
            return

        # 如果时间到了，自动交卷
        if remaining_time <= 0 and not self.exam_submitted:
            self.submit_exam()
        else:
            # 1秒后再次更新
            self.root.after(1000, self.update_timer)

    def submit_exam(self):
        """提交考试"""
        if self.exam_submitted:
            return

        # 标记为已提交
        self.exam_submitted = True

        # 提交考试并获取结果
        result = self.exam_service.submit_exam(self.exam_id, self.exam_answers, self.exam_start_time)

        # 显示考试结果
        self.show_exam_result(result)

    def show_exam_result(self, result):
        """显示考试结果"""
        # 清空窗口
        for widget in self.root.winfo_children():
            widget.destroy()

        # 创建返回按钮 - 图片形式
        back_img = Image.open(resource_path(os.path.join("icon", "back.png")))
        back_img = back_img.resize((30, 30), Image.Resampling.LANCZOS)
        back_photo = ImageTk.PhotoImage(back_img)
        back_btn = tk.Label(self.root, image=back_photo, cursor="hand2")
        back_btn.image = back_photo  # 保持引用
        back_btn.bind("<Button-1>", lambda e: self.on_back())
        back_btn.pack(anchor=tk.NW, pady=10, padx=10)

        # 考试结果标题
        title_label = tk.Label(self.root, text="考试结果", font=self.font)
        title_label.pack(pady=10)

        # 计算成绩和通过率
        correct_count = result['correct_count']
        total_count = result['total_count']
        pass_score = self.exam_config['pass_score']
        pass_exam = correct_count >= pass_score

        # 判断是否通过考试
        pass_status = "通过" if pass_exam else "未通过"
        status_color = "green" if pass_exam else "red"

        # 显示结果信息（带图片）
        # 加载图片并调整大小
        if pass_exam:
            status_img = Image.open(resource_path(os.path.join("icon", "passed.png")))
        else:
            status_img = Image.open(resource_path(os.path.join("icon", "no_pass.png")))
        status_img = status_img.resize((80, 60), Image.Resampling.LANCZOS)
        status_photo = ImageTk.PhotoImage(status_img)

        # 创建带图片和文字的标签
        status_label = ttk.Label(self.root, text=f"考试结果: {pass_status}", font=self.font, foreground=status_color,
                               image=status_photo, compound=tk.LEFT)
        status_label.image = status_photo  # 保持引用
        status_label.pack(pady=10)

        result_label = tk.Label(self.root, text=f"总题数: {total_count}\n答对题数: {correct_count}\n得分: {correct_count}/{total_count}", font=self.font, justify=tk.LEFT)
        result_label.pack(pady=10, padx=20, anchor=tk.W)

        # 按钮框架
        btn_frame = tk.Frame(self.root)
        btn_frame.pack(pady=20)

        # 查看考卷按钮 - 图片+文字形式
        look_paper_img = Image.open(resource_path(os.path.join("icon", "look_paper.png")))
        look_paper_img = look_paper_img.resize((30, 30), Image.Resampling.LANCZOS)
        look_paper_photo = ImageTk.PhotoImage(look_paper_img)
        review_btn = tk.Label(btn_frame, image=look_paper_photo, text="查看考卷", font=self.font, fg="white",
                             cursor="hand2", compound=tk.LEFT, bg="#4a7abc")
        review_btn.image = look_paper_photo  # 保持引用
        review_btn.bind("<Button-1>", lambda e: self.review_exam(self.exam_id))
        review_btn.pack(side=tk.LEFT, padx=10)

    def review_exam(self, exam_id):
        # print(f"exam_id: {exam_id}")
        # 使用service获取考试基本信息
        exam_record = self.exam_service.get_exam_record_by_id(exam_id)
        # print(f"exam_record: {exam_record}")
        # 使用service获取考试题目详情
        question_details = self.exam_service.get_exam_question_details(exam_id)
        # print(f"question_details: {question_details}")
        # 准备考试题目数据和用户答案
        exam_questions = []
        user_answers = {}
        
        # 清空窗口
        for widget in self.root.winfo_children(): 
            widget.destroy()

        # 创建返回按钮 - 图片形式
        back_img = Image.open(resource_path(os.path.join("icon", "back.png")))
        back_img = back_img.resize((30, 30), Image.Resampling.LANCZOS)  # 调整图片大小
        back_photo = ImageTk.PhotoImage(back_img)
        back_btn = tk.Label(self.root, image=back_photo, cursor="hand2")
        back_btn.image = back_photo  # 保持引用
        back_btn.bind("<Button-1>", lambda e: self.on_back())
        back_btn.pack(anchor=tk.NW, pady=10, padx=10)

        # 显示考试信息和标题
        if exam_record:
            exam_info_text = f"考试类别: {exam_record.category} | 考试日期: {exam_record.exam_date}"
            info_label = tk.Label(self.root, text=exam_info_text, font=self.font)
            info_label.pack(pady=5)

        title_label = tk.Label(self.root, text="考卷回顾", font=self.title_font)
        title_label.pack(pady=10)

        # 创建滚动条和画布 (使用ttkbootstrap样式)
        canvas = ttkb.Canvas(self.root)
        scrollbar = ttkb.Scrollbar(self.root, orient="vertical", command=canvas.yview, bootstyle="success-vertical")
        scrollable_frame = ttkb.Frame(canvas)

        scrollable_frame.bind(
            "<Configure>",
            lambda e: canvas.configure(
                scrollregion=canvas.bbox("all")
            )
        )

        if question_details:
            for qd in question_details:
                # 使用ExamQuestionDetail对象构建题目信息
                question_dict = {
                    'id': qd.question_id,  # 题目ID
                    'Q': qd.question_text,   # 题目文本
                    'A': qd.option_a,   # 选项A
                    'B': qd.option_b,   # 选项B
                    'C': qd.option_c,   # 选项C
                    'D': qd.option_d,   # 选项D
                    'T': qd.correct_answer,   # 正确答案
                    'type': qd.type,  # 题目类型
                    'F': qd.image_data   # 图片数据
                }
                exam_questions.append(question_dict)
                
                # 存储用户答案（键为题目ID，值为(用户答案, 是否正确)）
                user_answers[qd.question_id] = (qd.user_answer, qd.is_correct)

                # 创建题目框架
                question_frame = tk.Frame(scrollable_frame)
                question_frame.pack(fill='x', padx=20, pady=10)

                # 显示题目文本（添加自动换行）
                question_text = f"{len(exam_questions)}. {question_dict['Q']}"
                question_label = tk.Label(question_frame, text=question_text, font=self.font, anchor='w', justify='left', wraplength=900)
                question_label.pack(anchor='w', pady=5)

                # 显示图片（如果有）
                if 'F' in question_dict and question_dict['F'] and question_dict['F'].startswith('data:image/png;base64,'):
                    try:
                        import base64
                        from io import BytesIO
                          # 提取base64数据
                        base64_data = question_dict['F'].replace('data:image/png;base64,', '')
                        # 解码base64数据为图片
                        image_data = base64.b64decode(base64_data)
                        image = Image.open(BytesIO(image_data))

                        # 调整图片大小
                        max_width = 400
                        max_height = 180
                        width, height = image.size
                        ratio = min(max_width/width, max_height/height)
                        new_width = int(width * ratio)
                        new_height = int(height * ratio)
                        resized_image = image.resize((new_width, new_height), Image.LANCZOS)

                        # 创建PhotoImage对象
                        photo = ImageTk.PhotoImage(resized_image)

                        # 创建标签并显示图片
                        image_label = tk.Label(question_frame, image=photo)
                        image_label.image = photo  # 保持引用，防止被垃圾回收
                        image_label.pack(anchor='w', pady=5)
                    except Exception as e:
                        error_label = tk.Label(question_frame, text=f"图片加载失败: {str(e)}", font=self.font, fg='red')
                        error_label.pack(anchor='w', pady=5)

                # 显示选项
                option_frame = tk.Frame(question_frame)
                option_frame.pack(anchor='w', padx=10)

                options = [('A', question_dict['A']), ('B', question_dict['B']), ('C', question_dict['C']), ('D', question_dict['D'])]
                for opt_letter, opt_text in options:
                    # 检查是否是正确答案或用户选择的答案
                    # 对于多选题，正确答案可能是多个选项的组合
                    is_correct_option = opt_letter in question_dict['T']
                    bg_color = 'lightgreen' if is_correct_option else 'white'
                    
                    # 检查用户是否选择了该选项
                    user_ans = user_answers[question_dict['id']][0]
                    if user_ans and user_ans != '-1' and opt_letter in user_ans:
                        if user_answers[question_dict['id']][1]:
                            bg_color = 'lightgreen'
                        else:
                            bg_color = 'lightcoral'

                    # 选项文本添加自动换行和正确答案标记
                    opt_text_with_mark = f"{opt_letter}: {opt_text}{' (√)' if is_correct_option else ''}"
                    # 使用ttkbootstrap标签和bootstyle设置样式
                    style = "success" if bg_color == 'lightgreen' else "danger" if bg_color == 'lightcoral' else "secondary"
                    opt_label = ttkb.Label(option_frame, text=opt_text_with_mark, font=self.font, anchor='w', 
                                          bootstyle=style, wraplength=900, justify='left')
                    opt_label.pack(anchor='w', pady=2)

                # 显示用户答案和正确性
                user_ans, is_correct = user_answers[question_dict['id']]
                user_answer_text = "未作答" if user_ans in ['-1', '', None] else user_ans
                result_text = f"你的答案: {user_answer_text} | {'正确' if is_correct else '错误'}"
                result_color = 'green' if is_correct else 'red'
                result_label = ttkb.Label(question_frame, text=result_text, font=self.font, 
                                         bootstyle="success" if is_correct else "danger")
                result_label.pack(anchor='w', pady=5)
        else:
            # 没有找到题目详情时显示提示
            empty_label = tk.Label(scrollable_frame, text="没有找到该考试的题目详情", font=self.font)
            empty_label.pack(pady=20)

        canvas.create_window((0, 0), window=scrollable_frame, anchor="nw")
        canvas.configure(yscrollcommand=scrollbar.set)

        canvas.pack(side="left", fill="both", expand=True)
        scrollbar.pack(side="right", fill="y")

        # 绑定鼠标滚轮事件
        def _on_mouse_wheel(event):
            try:
                canvas.yview_scroll(-1 * (event.delta // 120), "units")
            except tk.TclError:
                # 当canvas被销毁时，忽略错误
                pass

        canvas.bind_all("<MouseWheel>", _on_mouse_wheel)

        # 在窗口关闭时移除事件绑定
        self.root.protocol("WM_DELETE_WINDOW", lambda: (canvas.unbind_all("<MouseWheel>"), self.root.destroy()))